#ifndef QUEUE
#define QUEUE
template<typename TContainer>
class Queue
{
public:
	using ValueType = typename TContainer::ValueType;
	using ExceptionType = int;
	static constexpr int NoCapacityLimit = -1;
	static constexpr ExceptionType QueueEmpty = -1;
	static constexpr ExceptionType QueueFull = -2;
public:
	Queue(int capacity = NoCapacityLimit);
	Queue(const Queue&) = delete;
	Queue(Queue&&) = delete;
	~Queue();
	int Count();
	ValueType DeQueue();
	ValueType& Front();
	ValueType& Rear();
	void EnQueue(const ValueType& value);
	void Clear();
private:
	TContainer* pContainer;
	int capacity;
};

template<typename TContainer>
Queue<TContainer>::Queue(int capacity)
{
	this->capacity = capacity;
	this->pContainer = new TContainer();
}

template<typename TContainer>
Queue<TContainer>::~Queue()
{
	delete this->pContainer;
}

template<typename TContainer>
int Queue<TContainer>::Count()
{
	return this->pContainer->Count();
}

template<typename TContainer>
typename Queue<TContainer>::ValueType Queue<TContainer>::DeQueue()
{
	if (this->Count() == 0)
	{
		throw QueueEmpty;
	}
	ValueType value = *(this->pContainer->Begin());
	this->pContainer->Remove(this->pContainer->Begin());
	return value;
}

template<typename TContainer>
typename Queue<TContainer>::ValueType& Queue<TContainer>::Front()
{
	if (this->Count() == 0)
	{
		throw QueueEmpty;
	}
	return *(this->pContainer->Begin());
}

template<typename TContainer>
typename Queue<TContainer>::ValueType& Queue<TContainer>::Rear()
{
	if (this->Count() == 0)
	{
		throw QueueEmpty;
	}
	return *(this->pContainer->ReversedBegin());
}

template<typename TContainer>
void Queue<TContainer>::EnQueue(const ValueType& value)
{
	if (this->Count() == this->capacity)
	{
		throw QueueFull;
	}
	this->pContainer->Insert(value, this->pContainer->End());
}

template<typename TContainer>
void Queue<TContainer>::Clear()
{
	delete this->pContainer;
	this->pContainer = new TContainer();
}

#endif // !QUEUE

